﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

//using NPOI.SS.UserModel;
//using NPOI.XSSF.UserModel;

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

using Core;
using Core.Enumerations;
using Core.Attributes;
using Core.Result;

namespace Storage
{
    /// <summary>
    /// 
    /// </summary>
    class ExcelResultStorage : AbstractResultStorage
    {
        SpreadsheetDocument document;
        WorkbookPart workbook;
        int currentAddedGlobalRow = 0;

        public ExcelResultStorage(string str)
            : base(str)
        {
            // TODO maybe exception will be thrown
            if (!storageStr.EndsWith(Path.DirectorySeparatorChar.ToString()))
            {
                storageStr += Path.DirectorySeparatorChar;
            }
        }

        public override StorageType GetStorageType()
        {
            return StorageType.ExcelStorage;
        }

        public override void Save(ResearchResult result)
        {
            if (!Directory.Exists(storageStr))
            {
                Directory.CreateDirectory(storageStr);
            }

            string fileName = storageStr + result.ResearchName;
            if (File.Exists(fileName + ".xls") || File.Exists(fileName + ".xlsx"))
                fileName += result.ResearchID;

            document = SpreadsheetDocument.Create(fileName + ".xlsx", SpreadsheetDocumentType.Workbook);
            workbook = document.AddWorkbookPart();
            workbook.Workbook = new Workbook();

            // Add a WorksheetPart to the WorkbookPart.
            WorksheetPart worksheetPart = workbook.AddNewPart<WorksheetPart>();
            worksheetPart.Worksheet = new Worksheet(new SheetData());

            // Add Sheets to the Workbook.
            Sheets sheets = document.WorkbookPart.Workbook.
                AppendChild<Sheets>(new Sheets());

            // Append a new worksheet and associate it with the workbook.
            Sheet sheet = new Sheet()
            {
                Id = document.WorkbookPart.
                    GetIdOfPart(worksheetPart),
                SheetId = 1,
                Name = "mySheet"
            };
            sheets.Append(sheet);

            /*SaveResearchInfo(result.ResearchID, result.ResearchName,
                    result.ResearchType, result.ModelType, result.RealizationCount,
                    result.Size, result.Edges);
            SaveResearchParameters(result.ResearchParameterValues);
            SaveGenerationParameters(result.GenerationParameterValues);

            for (int i = 0; i < result.EnsembleResults.Count; ++i)
            {
                SaveEnsembleResult(result.EnsembleResults[i], i);
            }*/

            workbook.Workbook.Save();
            document.Close();
        }

        public override void Delete(Guid researchID)
        {
            throw new NotImplementedException();
        }

        public override List<ResearchResult> LoadAllResearchInfo()
        {
            throw new NotImplementedException();
        }

        public override ResearchResult Load(Guid researchID)
        {
            throw new NotImplementedException();
        }

        #region Utilities

        private void SaveResearchInfo(Guid researchID,
            string researchName,
            ResearchType rType,
            ModelType mType,
            int realizationCount,
            UInt32 size,
            Double edges)
        {
            WorksheetPart worksheetPart = workbook.AddNewPart<WorksheetPart>();
            Sheet researchInfoSheet = new Sheet() { Id = workbook.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Research Info" };

            /*IRow rowID = researchInfoSheet.CreateRow(0);
            rowID.CreateCell(0).SetCellValue("ResearchID");
            rowID.CreateCell(1).SetCellValue(researchID.ToString());

            IRow rowName = researchInfoSheet.CreateRow(1);
            rowName.CreateCell(0).SetCellValue("ResearchName");
            rowName.CreateCell(1).SetCellValue(researchName);

            IRow rowType = researchInfoSheet.CreateRow(2);
            rowType.CreateCell(0).SetCellValue("ResearchType");
            rowType.CreateCell(1).SetCellValue(rType.ToString());

            IRow rowModel = researchInfoSheet.CreateRow(3);
            rowModel.CreateCell(0).SetCellValue("ModelType");
            rowModel.CreateCell(1).SetCellValue(mType.ToString());

            IRow rowRCount = researchInfoSheet.CreateRow(4);
            rowRCount.CreateCell(0).SetCellValue("RealizationCount");
            rowRCount.CreateCell(1).SetCellValue(realizationCount);

            IRow rowDate = researchInfoSheet.CreateRow(5);
            rowDate.CreateCell(0).SetCellValue("Date");
            rowDate.CreateCell(1).SetCellValue(DateTime.Now.ToString());

            IRow rowSize = researchInfoSheet.CreateRow(6);
            rowSize.CreateCell(0).SetCellValue("Size");
            rowSize.CreateCell(1).SetCellValue(size);

            IRow rowEdges = researchInfoSheet.CreateRow(7);
            rowEdges.CreateCell(0).SetCellValue("Edges");
            rowEdges.CreateCell(1).SetCellValue(edges);*/
        }

        private void SaveResearchParameters(Dictionary<ResearchParameter, object> p)
        {
            /*if (p.Count != 0)
            {
                ISheet researchParametersSheet = workbook.CreateSheet("Research Parameters");
                researchParametersSheet.SetDefaultColumnStyle(0, style);
                researchParametersSheet.SetDefaultColumnStyle(1, style);
                researchParametersSheet.SetColumnWidth(0, 20 * 256);
                researchParametersSheet.SetColumnWidth(1, 20 * 256);

                int i = 0;
                foreach (ResearchParameter rp in p.Keys)
                {
                    if (p[rp] != null)
                    {
                        IRow r = researchParametersSheet.CreateRow(i);
                        r.CreateCell(0).SetCellValue(rp.ToString());
                        r.CreateCell(1).SetCellValue(p[rp].ToString());
                        ++i;
                    }
                }
            }*/
        }

        private void SaveGenerationParameters(Dictionary<GenerationParameter, object> p)
        {
            /*ISheet genParametersSheet = workbook.CreateSheet("Generation Parameters");
            genParametersSheet.SetDefaultColumnStyle(0, style);
            genParametersSheet.SetDefaultColumnStyle(1, style);
            genParametersSheet.SetColumnWidth(0, 20 * 256);
            genParametersSheet.SetColumnWidth(1, 20 * 256);

            int i = 0;
            foreach (GenerationParameter gp in p.Keys)
            {
                if (p[gp] != null)
                {
                    IRow r = genParametersSheet.CreateRow(i);
                    r.CreateCell(0).SetCellValue(gp.ToString());
                    r.CreateCell(1).SetCellValue(p[gp].ToString());
                    ++i;
                }
            }*/
        }

        private void SaveEnsembleResult(EnsembleResult e, int id)
        {
            /*foreach (AnalyzeOption opt in e.Result.Keys)
            {
                AnalyzeOptionInfo info = ((AnalyzeOptionInfo[])opt.GetType().GetField(opt.ToString()).GetCustomAttributes(typeof(AnalyzeOptionInfo), false))[0];
                OptionType optionType = info.OptionType;

                switch (optionType)
                {
                    case OptionType.Global:
                        SaveToGlobalSheet(opt.ToString(), e.Result[opt].ToString());
                        break;
                    case OptionType.ValueList:
                        SaveValueListSheet(info, e.Result[opt]);
                        break;
                    case OptionType.Distribution:
                    case OptionType.Trajectory:
                        SaveDistributionSheet(info, e.Result[opt]);
                        break;
                    default:
                        break;
                }
            }*/
        }

        private void SaveToGlobalSheet(string optName, string optValue)
        {
            /*ISheet globalSheet = workbook.GetSheet("Global");
            if (globalSheet == null)
            {
                globalSheet = workbook.CreateSheet("Global");
            }

            globalSheet.SetDefaultColumnStyle(0, style);
            globalSheet.SetDefaultColumnStyle(1, style);
            globalSheet.SetColumnWidth(0, 20 * 256);
            globalSheet.SetColumnWidth(1, 40 * 256);

            IRow r = globalSheet.CreateRow(currentAddedGlobalRow);
            r.CreateCell(0).SetCellValue(optName);
            r.CreateCell(1).SetCellValue(optValue);
            ++currentAddedGlobalRow;*/
        }

        private void SaveValueListSheet(AnalyzeOptionInfo info, Object value)
        {
            /*if (info.EnsembleResultType.Equals(typeof(List<Double>)))
            {
                ISheet valueListSheet = workbook.CreateSheet(info.FullName);
                valueListSheet.SetDefaultColumnStyle(0, style);
                valueListSheet.SetColumnWidth(0, 20 * 256);

                List<Double> l = value as List<Double>;
                int i = 0;
                foreach (Double d in l)
                {
                    IRow r = valueListSheet.CreateRow(i);
                    r.CreateCell(0).SetCellValue(d);
                    ++i;
                }
            }*/
        }

        private void SaveDistributionSheet(AnalyzeOptionInfo info, Object value)
        {
            /*int length = (info.FullName.Length > 31) ? 30 : info.FullName.Length;
            ISheet distributionSheet = workbook.CreateSheet(info.FullName.Substring(0, length));
            distributionSheet.SetDefaultColumnStyle(0, style);
            distributionSheet.SetDefaultColumnStyle(1, style);
            distributionSheet.SetColumnWidth(0, 20 * 256);
            distributionSheet.SetColumnWidth(1, 20 * 256);

            IRow headerRow = distributionSheet.CreateRow(0);
            headerRow.CreateCell(0).SetCellValue(info.XAxisName);
            headerRow.CreateCell(1).SetCellValue(info.YAxixName);

            int i = 1;
            if (info.EnsembleResultType.Equals(typeof(SortedDictionary<Double, Double>)))
            {
                SortedDictionary<Double, Double> l = value as SortedDictionary<Double, Double>;
                foreach (Double d in l.Keys)
                {
                    IRow row = distributionSheet.CreateRow(i);
                    row.CreateCell(0).SetCellValue(d);
                    row.CreateCell(1).SetCellValue(l[d]);
                    ++i;
                }
            }
            else if (info.EnsembleResultType.Equals(typeof(SortedDictionary<UInt32, Double>)))
            {
                SortedDictionary<UInt32, Double> l = value as SortedDictionary<UInt32, Double>;
                foreach (UInt32 d in l.Keys)
                {
                    IRow row = distributionSheet.CreateRow(i);
                    row.CreateCell(0).SetCellValue(d);
                    row.CreateCell(1).SetCellValue(l[d]);
                    ++i;
                }
            }
            else if (info.EnsembleResultType.Equals(typeof(SortedDictionary<UInt16, Double>)))
            {
                SortedDictionary<UInt16, Double> l = value as SortedDictionary<UInt16, Double>;
                foreach (UInt16 d in l.Keys)
                {
                    IRow row = distributionSheet.CreateRow(i);
                    row.CreateCell(0).SetCellValue(d);
                    row.CreateCell(1).SetCellValue(l[d]);
                    ++i;
                }
            }*/
        }

        #endregion
    }
}